-- EventMgr
-- Create by zouyb
-- 事件管理器

module("EventMgr", package.seeall);

-- 所有的事件ID列表
require("core/base/Compiler");
update("game/logic/base/EventConst");
update("core/module/Profiler");

-- 所有的事件信息
local events = {};

-- 所有的绑定信息
local bindInfos = {};

function init()
    events = get_daemon_data("EventMgr", "events") or {};
    bindInfos = get_daemon_data("EventMgr", "bindInfos") or {};
end

function destruct()
    register_daemon_data("EventMgr", "events", events);
    register_daemon_data("EventMgr", "bindInfos", bindInfos);
end

-- 注册一个事件
function register(name, eventId, f)
    events[eventId] = events[eventId] or {};

    -- 如果已经有同名的关注者，报个错(禁止同名的事件监听者)
    for _, info in ipairs(events[eventId]) do
        if info.name == name then
            if DEBUG_MODE == 1 or DEBUG_MODE == true then
                assert(false, string.format("Warning:事件%s<ID:0x%04X>重复注册了", name, eventId));
            else
                cclog(string.format("Warning:事件%s<ID:0x%04X>重复注册了", name, eventId));
            end
        end
    end

    -- 记录起来
    table.insert(events[eventId], {name = name, func = f});
end

-- 反注册事件
function remove(name, eventId)
    if not events[eventId] then return end

    for i, info in ipairs(events[eventId]) do
        if info.name == name then
            events[eventId][i] = nil;
            break;
        end
    end
    clean_array(events[eventId]);

    -- 若为空数组，则清除该事件
    if table.getn(events[eventId]) == 0 then
        events[eventId] = nil;
    end
end

-- 反注册所有的事件
function removeAll(name)
    for eventId, info in pairs(events) do
        remove(name, eventId);
    end
end

-- 触发事件
function fire(eventId, params)
    Profiler.funcBegin("EventM:fire");

    local l = bindInfos[eventId];
    if l then
        for k, _ in pairs(l) do
            -- 检查绑定模块是否已经加载，如果未加载，此处会自动加载
            if _G[k] then end;
        end
    end

    if not events[eventId] then return end

    -- 这里需要拷贝一下，防止遍历的过程中table的值被篡改
    local eventList = table.copy(events[eventId]);

    for _, info in ipairs(eventList) do
        if info.func then
            local status, err = xpcall(function() info.func(params); end, __G__TRACKBACK__);
            if not status then
                print(err);
            end
        end
    end
    Profiler.funcEnd("EventM:fire");
end

-- 绑定事件
function bind(name, eventId)
    bindInfos[eventId] = bindInfos[eventId] or {};

    bindInfos[eventId][name] = true;
end

-- 查询事件
function queryEvent(eventId)
    cclog("%o", events[eventId]);
end

-- 查询绑定事件
function queryBindEvent(eventId)
    cclog("%o", bindInfos[eventId]);
end
